package com.desetalk.service;

import java.util.Scanner;

import io.netty.bootstrap.Bootstrap;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.codec.LengthFieldBasedFrameDecoder;
import io.netty.handler.codec.LengthFieldPrepender;
import io.netty.handler.codec.protobuf.ProtobufDecoder;
import io.netty.handler.codec.protobuf.ProtobufEncoder;
import com.desetalk.client.ClientHandler;
import com.desetalk.client.cmd.Command;
import com.desetalk.proto.RequestProtocol;
import com.desetalk.proto.ResponseProtocol;
import com.desetalk.proto.ResponseProtocol.Response;
import com.desetalk.util.ValidateUtil;

import android.app.Service;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;

import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
import android.support.v4.content.LocalBroadcastManager;

public class NettyService extends Service {

	private final String host = "192.168.1.107";
	private final int port = 8989;
	private BroadcastReceiver mMessageReceiver;
	private Handler handler;
	private Response response;
	EventLoopGroup group = new NioEventLoopGroup();
	ClientHandler cHandler = new ClientHandler();
	Channel ch = null;

	@Override
	public int onStartCommand(Intent intent, int flags, int startId) {
		// TODO Auto-generated method stub
		startUp();
		handler = new Handler() {
			@Override
			public void handleMessage(Message msg) {// 返回response
				// TODO Auto-generated method stub
				response=(Response) msg.obj;
				Intent intent = new Intent("local_receiver");
				// You can also include some extra data.
				Bundle bundle = new Bundle();
				bundle.putSerializable("message",response);
				intent.putExtras(bundle);
				LocalBroadcastManager.getInstance(getApplicationContext()).sendBroadcast(intent);
				super.handleMessage(msg);
			}
		};

		setUiHandler(handler);
		mMessageReceiver = new BroadcastReceiver() {// 接受命令
			@Override
			public void onReceive(Context context, Intent intent) {
				// Get extra data included in the Intent
				String message = intent.getStringExtra("cmd");
				sendCommand(message);
			}
		};
		LocalBroadcastManager.getInstance(getApplicationContext()).registerReceiver(
				mMessageReceiver, new IntentFilter("local_sender"));
		return super.onStartCommand(intent, flags, startId);
	}

	public boolean stopNetty() {
		try {
			stop();
			stopSelf();
			return true;
		} catch (Exception e) {
			return false;
		}

	}

	public void startUp() {

		try {
			Bootstrap b = new Bootstrap();
			b.group(group).channel(NioSocketChannel.class)
					.handler(new ChannelInitializer<SocketChannel>() {
						@Override
						public void initChannel(SocketChannel ch)
								throws Exception {
							ChannelPipeline p = ch.pipeline();
							p.addLast("frameDecoder",
									new LengthFieldBasedFrameDecoder(1048576,
											0, 4, 0, 4));
							p.addLast(
									"protobufDecoder",
									new ProtobufDecoder(
											ResponseProtocol.Response
													.getDefaultInstance()));

							p.addLast("frameEncoder", new LengthFieldPrepender(
									4));
							p.addLast("protobufEncoder", new ProtobufEncoder());

							p.addLast("handler", cHandler);
						}
					});

			// Make a new connection.
			ch = b.connect(host, port).sync().channel();
		} catch (Exception e) {

		}
	}

	public void sendCommand(String input) {
		ChannelFuture lastWriteFuture = null;
		if (ValidateUtil.isValid(input)) {
			input = input.trim();
			Scanner sc = new Scanner(input);
			String cmdStr = sc.next();
			Command cmd = null;
			try {
				cmd = (Command) Class.forName(
						"com.desetalk.client.cmd.impl."
								+ toUpperCaseFirstOne(cmdStr) + "Command")
						.newInstance();
				RequestProtocol.Request.Builder builder = cmd.execute(input);
				if (ValidateUtil.isValid(builder)) {
					lastWriteFuture = ch.writeAndFlush(builder.build());
				}
			} catch (ClassNotFoundException e) {
				System.out.println("command: " + cmdStr + " not found");
			} catch (InstantiationException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} catch (IllegalAccessException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		// Thread.sleep(1000);
		if (lastWriteFuture != null) {
			try {
				lastWriteFuture.sync();
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
	}

	public void setUiHandler(Handler h) {
		cHandler.setUiHandler(h);
	}

	public Handler getUiHandler() {
		return cHandler.getUiHandler();
	}

	public void stop() {
		try {
			group.shutdownGracefully();
		} catch (Exception e) {

		}
	}

	public static String toUpperCaseFirstOne(String s) {
		if (Character.isUpperCase(s.charAt(0)))
			return s;
		else
			return (new StringBuilder())
					.append(Character.toUpperCase(s.charAt(0)))
					.append(s.substring(1)).toString();
	}

	@Override
	public IBinder onBind(Intent intent) {
		// TODO Auto-generated method stub
		return null;
	}
}
